﻿@Cofe ?= {}

$ = jQuery
Entry = Cofe.Entry
EntryItem = Cofe.EntryItem
EntryList = Cofe.EntryList
Link = Cofe.Link
utils = Cofe.utils


# CONTROLLER - Base class for represent a number of EntryItems (controller), 
#              which is Entries (model) generated from EntryList (model).
#     params - @el
#     events - fetchStarted, fetchSuccess, fetchFailed, itemAdded, itemRemoved, itemClicked, refreshing, refreshed
#
# ps: EntryItemListBase in Cofe2
class EntryItemList extends Spine.Controller  
  @include Cofe.paginateSupport
  @include Cofe.waypointSupport
  @include Cofe.selectSupport

  tag : "ul"
  childTag : "li"
  childTemplate : $.templates("#entryTemplate")
  waypoint : false
  select : 'none' # none / one / multi
  entryFilter : (entryItem) -> true

  elements : 
    ".entryList" : "eleEntryList"                  # ul element with data-role="listview"   

  constructor : (constructionParam) ->    
    @entryItems = [] 
    @allEntryItems = []
    @refreshMode = "replace" #replace / append
    super

  init : () ->
    #console.log(@el)
    if @waypoint
        @initWaypoint(@)
    switch @select
      when "one"
        @initSingleSelect(@)
      when "multi"
        @initMultiSelect(@)
    @
        
  ### Event handlers ###
  
  # handles EntryItem.clicked event.
  onItemClicked : (sender) =>
    @itemClicked(sender, sender.entry)

  # handles @EntryList.fetched event
  onListFetched : (sender) =>
    @trigger("fetchSuccess", @, sender)
    @refresh(sender)    

  # handles @EntryList.error event
  onListError : (sender, errorStr, textStatus, xhr) =>
    log.error("EntryItemList: List failed - " + errorStr)    
    @trigger("error", @, xhr.status + " " + xhr.statusText, @entryList.url)
    @trigger("fetchFailed", @, errorStr, textStatus, xhr)

  ### Methods ###

  #Find all entry items, that match an id, label or your func
  #e.g. _eilist1.findAll(function(e) { return e.id == "1"})
  #e.g. _eilist1.findAll("1")
  #e.g. _eilist1.findAll("testParse1.txt")
  findAll : (lookup) =>
    lookupFunc = (ei) -> false
    switch (typeof  lookup)
      when "string"
        lookupFunc = (ei) -> ei.entry.id == lookup || ei.entry.label == lookup
      when "function" 
        lookupFunc = lookup 
      else throw "Not supported"

    return (entryItem for entryItem in @entryItems when lookupFunc(entryItem))       

  #Find the first entry item, that match id, label or your func, return undefined if not found.
  #e.g. _eilist1.find(function(e) { return e.id == "1"})
  #e.g. _eilist1.find("1")
  #e.g. _eilist1.find("testParse1.txt")
  find : (lookup) =>
    result = @findAll(lookup)    
    if (result.length > 0)
      return result[0]
    return undefined

  # Overridable, called by onPathChanged() after App.pathChanged event (if bound) is raised.
  # accept a link or a path.
  changeUrlPath : (url) =>      
    @refreshMode = "replace"
    @changeEntryList(EntryList.fromUrl(url))
  
  changeEntryList : (entryList) =>    
    @trigger("pathChanging", entryList.url, entryList)

    #unbind last entryList if exits
    @entryList?.unbind("fetched", @onListFetched)    
    @entryList?.unbind("error", @onListError)

    #initalize new entryList
    @entryList = entryList
         
    if @entryList.status isnt "ready"           
      @entryList.bind("fetched", @onListFetched)      
      @entryList.bind("error", @onListError)            
      @entryList.fetch()   
      @trigger("fetchStarted", @, entryList)    
    else
      @refresh(@entryList)

    @trigger("pathChanged", entryList.url, entryList)    

  # Used by internal to add or remove item.
  addItem : (entryItem, idx) =>
    #console.log "add" + idx
    @allEntryItems.splice(idx, 0, entryItem)    
    @el.append(entryItem.render(@childTemplate))    
    @trigger("itemAdded", @, entryItem, idx)    
    
  removeItem : (entryItem, idx) =>
    @allEntryItems.splice(idx, 1)    
    entryItem.el.remove()
    @trigger("itemRemoved", @, entryItem, idx)

  # Convert EntryList (model)'s entries to EntryItem (controller), 
  # parameter - entryList - which contains items  
  # -> store it to @entryItems, @folderItems and @fileItems    
  # -> raise refreshed event.
  refresh : (entryList) =>        
    if entryList is undefined then entryList = @entryList
    if entryList is undefined then throw "EntryList not specified."
    log.debug("EntryItemList: refreshing " + entryList.entries.length + " items") 
    
    @trigger("refreshing", @, entryList)
      
    newEntryItems = (for entry in entryList.entries when @entryFilter(entry)
      @entryItemConstructor(entry))

    if @refreshMode == "replace" 
       @removeItem(eItem, @entryItems.length - idx) for eItem, idx in @entryItems.reverse()
       @entryItems = newEntryItems
       @addItem(eItem, idx) for eItem, idx in newEntryItems
    else 
       orgLen = @entryItems.length
       @entryItems = @entryItems.concat(newEntryItems)
       @addItem(eItem, idx + orgLen) for eItem, idx in newEntryItems             

    
    @folderItems = []
    @fileItems = []
    (if entryItem.entry.isContainer() then @folderItems else @fileItems).push entryItem for entryItem in @entryItems
    
    @status = "done"    
    @trigger("refreshed", @, entryList)
 
  reload : () =>
    @entryList?.fetch()
     
  # Overrideable, Given an entry, construct the controller (e.g. EntryItem / EntryTreeItem) for the entry.
  entryItemConstructor : (entry) ->
    return new EntryItem({
        entry: entry
        tag : @childTag
      })

  # Clear the rendered items.
  remove: =>    
    #@el.empty()  
    @eleEntryList.empty()

  empty : =>    
    #@el.empty()  
    @eleEntryList.empty()

  # Render the entryItems to the tag.
  render : () =>    
    log.debug("EntryItemList : Render " + @entryItems.length + "items")

    if @refreshMode == "replace" then @remove()
    for entryItem, idx in @entryItems                     # for each entry items (controllers)
      #@addItem(entryItem, idx)
      @el.append(entryItem.render(@childTemplate))   # calls it's render method, and append.    
    
    @el


    





Cofe.EntryItemList = EntryItemList
